package org.i0o.webplus;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期操作工具类
 * 
 * @author <a href="mailto:i0o@live.cn">黄腾飞</a>
 * @Created 2009-5-12
 */

public class DateUtil {
	/**
	 * 时间对比类型
	 */
	public enum CompareType {
		/**
		 * 用天为单位进行比较
		 */
		Day,

		/**
		 * 用小时为单位进行比较
		 */
		Hours,

		/**
		 * 用分钟为单位进行比较
		 */
		Minute
	}

	/**
	 * 日期计算，在指定日期基础上加减指定天数
	 * 
	 * @param date 指定日期
	 * @param days 要加减的天数
	 * @return 计算后的日期
	 */
	public static Date addDay(Date date, int days) {
		return computeDate(date, Calendar.DAY_OF_YEAR, days);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定天数
	 * 
	 * @param days 要加减的天数
	 * @return 计算后的日期
	 */
	public static Date addDay(int days) {
		return addDay(getCurrentDate(), days);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定小时
	 * 
	 * @param date 指定日期
	 * @param hours 要加减的小时
	 * @return 计算后的日期
	 */
	public static Date addHour(Date date, int hours) {
		return computeDate(date, Calendar.HOUR, hours);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定小时
	 * 
	 * @param hours 要加减的小时
	 * @return 计算后的日期
	 */
	public static Date addHoure(int hours) {
		return addHour(getCurrentDate(), hours);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定月
	 * 
	 * @param date 指定日期
	 * @param hours 要加减的月
	 * @return 计算后的日期
	 */
	public static Date addMonth(Date date, int months) {
		return computeDate(date, Calendar.MONTH, months);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定月
	 * 
	 * @param hours 要加减的月
	 * @return 计算后的日期
	 */
	public static Date addMonth(int months) {
		return addMonth(getCurrentDate(), months);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定周
	 * 
	 * @param date 指定日期
	 * @param hours 要加减的周
	 * @return 计算后的日期
	 */
	public static Date addWeek(Date date, int weeks) {
		return computeDate(date, Calendar.WEEK_OF_YEAR, weeks);
	}

	/**
	 * 日期计算，在当前日期基础上加减指定周
	 * 
	 * @param hours 要加减的周
	 * @return 计算后的日期
	 */
	public static Date addWeek(int weeks) {
		return addWeek(getCurrentDate(), weeks);
	}

	/**
	 * 时间清零，只留下原来的日期
	 * 
	 * @param date 原Date对象
	 * @return 清零后的日历对象
	 */
	public static Calendar calendarClear(Date date) {
		Calendar calendar = converDateToCalendar(date);

		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);

		return calendar;
	}

	/**
	 * 根据日历的规则，为给定的日历字段添加或减去指定的时间量。
	 * 
	 * @param date 要计算的日期
	 * @param field 日历字段
	 * @param amount 为字段添加的日期或时间量。
	 * @return
	 */
	public static Date computeDate(Date date, int field, int amount) {
		if (date == null) { return date; }

		Calendar calendar = converDateToCalendar(date);
		calendar.add(field, amount);

		return calendar.getTime();
	}

	/**
	 * 将Date转换成Calendar
	 * 
	 * @param date Date对象
	 * @return Calendar对象
	 */
	public static Calendar converDateToCalendar(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		return calendar;
	}

	/**
	 * 按指定格式格式化日期
	 * 
	 * @param date 日期
	 * @param formatStr 日期格式
	 * @return 格式化之后的字符
	 */
	public static String convertDateToStr(Date date, String formatStr) {
		formatStr = formatStr.trim();
		if (formatStr == null) { return null; }

		SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
		if (date == null) {
			return sdf.format(getCurrentDate());
		}
		else {
			return sdf.format(date);
		}
	}

	/**
	 * 将日期字符串按照yyyy-MM-dd模板进行转换
	 * 
	 * @param dateStr 日期字符串
	 * @return Date对象
	 * @throws ParseException
	 */
	public static Date convertStrToDate(String dateStr) throws ParseException {
		return convertStrToDate(dateStr, "yyyy-MM-dd");
	}

	/**
	 * 按照指定格式转换日期字符串
	 * 
	 * @param dateStr 日期字符串
	 * @param formatStr 日期格式,例如:yyyy-MM-dd hh:mm:ss
	 * @return Date对象
	 * @throws ParseException
	 */
	public static Date convertStrToDate(String dateStr, String formatStr) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
		return sdf.parse(dateStr);
	}

	/**
	 * 把字符串转换为数据库类型Timestamp。
	 * 
	 * @param dateStr 日期
	 * @param formatStr 日期格式
	 * @return 格式化之后的字符
	 * @throws ParseException
	 */
	public static Timestamp convertStrToTimestamp(String dateStr, String formatStr) throws ParseException {
		Date date = convertStrToDate(dateStr, formatStr);
		return new Timestamp(date.getTime());
	}

	/**
	 * 时间清零，只留下原来的日期
	 * 
	 * @param date 原Date对象
	 * @return 清零后的日期对象
	 */
	public static Date dateClear(Date date) {
		Calendar calendar = converDateToCalendar(date);

		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);

		return calendar.getTime();
	}

	/**
	 * 计算量时间之间的差
	 * 
	 * @param date 时间
	 * @param compareDate 要对比的时间
	 * @param compareType 对比类型
	 * @return 相差的时间
	 */
	public static String dateCompareTo(Date date, Date compareDate, CompareType compareType) {
		StringBuffer dateStr = new StringBuffer();
		int millisecond = 0;

		// 中文修饰
		switch (compareType) {
			case Minute:
				dateStr.append("分钟");
				millisecond = 60000;
				break;
			case Hours:
				dateStr.append("小时");
				millisecond = 3600000;
				break;
			case Day:
				dateStr.append("天");
				millisecond = 86400000;
				break;
		}

		// 处理Date
		long oldDate = date.getTime();
		long newDate = compareDate.getTime();

		// 计算
		long dispersion = (oldDate - newDate) / millisecond;

		// 处理负数
		if (oldDate - newDate < 0) {
			dispersion *= -1;
			dateStr.append("之前");
		}
		else {
			dateStr.append("之后");
		}

		return String.valueOf(dispersion) + dateStr.toString();
	}

	/**
	 * 获取自动时间格式
	 * 
	 * @param date 对比时间
	 * @return 表示时间的字符串
	 * @throws MyUtilException
	 */
	public static String getAutoTime(Date date) throws WebPlusException {
		// 获取当前时间
		Date now = getCurrentDate();

		long oldDate = date.getTime();
		long newDate = now.getTime();
		String dispersionDate = new String();

		if (oldDate - newDate >= 0) {
			// 抛出自定义异常
			throw new WebPlusException("对比时间不能晚于当前时间！");
		}
		else {
			// 计算时间差
			long dispersion = newDate - oldDate;

			// 判断
			if (dispersion < 360000) {
				dispersionDate = dateCompareTo(date, now, CompareType.Minute);
			}
			else if (dispersion > 900000 && dispersion < 1800000) {
				dispersionDate = "15分钟以前";
			}
			else if (dispersion > 1800000 && dispersion < 2700000) {
				dispersionDate = "30分钟以前";
			}
			else if (dispersion > 2700000 && dispersion < 3600000) {
				dispersionDate = "45分钟以前";
			}
			else if (dispersion < 10800000) {
				dispersionDate = dateCompareTo(date, now, CompareType.Hours);
			}
			else if (dispersion < 259200000) {
				dispersionDate = dateCompareTo(date, now, CompareType.Day);
			}
			else {
				dispersionDate = getDateStr();
			}
		}

		return dispersionDate;
	}

	/**
	 * 根据阿拉伯数字返回中文英文名称
	 * 
	 * @param weekNum 星期的阿拉伯数字
	 * @return 中文的星期名称
	 */
	public static String getCnWeek(int weekNum) {
		String[] weekStr = { "星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		return weekStr[weekNum];
	}

	/**
	 * 获取当前时间
	 * 
	 * @return 当前时间
	 */
	public static Date getCurrentDate() {
		return new Date(System.currentTimeMillis());
	}

	/**
	 * 按指定格式获取当前时间字符串
	 * 
	 * @param formatStr 日期格式
	 * @return 时间字符串
	 */
	public static String getCurrentDateStr(String formatStr) {
		return convertDateToStr(getCurrentDate(), formatStr);
	}

	/**
	 * 获得当前系统的时间戳
	 * 
	 * @return 从1970-1-1到现在的毫秒数
	 */
	public static long getCurrentTimeMillis() {
		return System.currentTimeMillis();
	}

	/**
	 * 得到系统当前时间的Timestamp对象
	 * 
	 * @return Timestamp对象
	 */
	public static Timestamp getCurrentTimestamp() {
		return new Timestamp(getCurrentTimeMillis());
	}

	/**
	 * 获取当前日期的字符串 yyyy-MM-dd
	 * 
	 * @return 当前日期的字符串
	 */
	public static String getDateStr() {
		return convertDateToStr(getCurrentDate(), "yyyy-MM-dd");
	}

	/**
	 * 获取当前日期和实践的字符串 yyyy-MM-dd HH:mm:ss
	 * 
	 * @return 当前日期和实践的字符串
	 */
	public static String getDateTimeStr() {
		return convertDateToStr(getCurrentDate(), "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 根据阿拉伯数字返回英文星期名称
	 * 
	 * @param weekNum 星期的阿拉伯数字
	 * @return 英文的星期名称
	 */
	public static String getEnWeek(int weekNum) {
		String[] weekStr = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "SaturDay" };
		return weekStr[weekNum];
	}

	/**
	 * 获取指定日期所在月份的第一天，时间清零
	 * 
	 * @param date 指定日期
	 * @return
	 */
	public static Date getFirstDayOfMonth(Date date) {
		if (date == null) { return date; }

		Calendar calendar = converDateToCalendar(date);
		calendar.set(Calendar.DATE, 1);

		return dateClear(calendar.getTime());
	}

	/**
	 * 把参数日期的时,分,秒清零,返回前一天<br/>
	 * 如:参数为2006-08-22 12:33 那么该方法返回 2006-08-23 00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getNextDay(Date date) {
		Calendar calendar = calendarClear(date);
		calendar.add(Calendar.DAY_OF_YEAR, 1);

		return calendar.getTime();
	}

	/**
	 * 把参数日期的时,分,秒清零,返回前一天<br/>
	 * 如:参数为2006-08-22 12:33 那么该方法返回 2006-08-21 00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getPreDay(Date date) {
		Calendar calendar = calendarClear(date);
		calendar.add(Calendar.DAY_OF_YEAR, -1);

		return calendar.getTime();
	}

	/**
	 * 获取当前时间的字符串 HH:mm:ss
	 * 
	 * @return 当前时间的字符串
	 */
	public static String getTimeStr() {
		return convertDateToStr(getCurrentDate(), "HH:mm:ss");
	}

	public static void main(String[] args) {
	}
}
